import router from '@/router'
import { useUserStore } from '@/stores'
import axios, { type Method } from 'axios'
import { showFailToast } from 'vant'

export const baseURL = 'https://consult-api.itheima.net/'

// 1. 创建实例，配置统一的基准路径和超时事件
const instance = axios.create({
  baseURL,
  timeout: 10000
})

// 请求发起的执行次序：1.执行请求拦截器 2.基于config请求配置对象发起真正的请求
// 3. 响应拦截器 4. 收到步骤3的返回值
instance.interceptors.request.use(
  // 2. 配置请求拦截器
  (config) => {
    // 判断当前是否有token，有的话（不管接口是否需要）携带给后台
    const store = useUserStore()
    if (store.user?.token && config.headers) {
      config.headers.Authorization = 'Bearer ' + store.user?.token
    }
    return config
  },
  (err) => {
    Promise.reject(err)
  }
)

// 响应拦截器的执行时机：在接口完整返回数据给前端时执行
instance.interceptors.response.use(
  // 3. http网络状态码2xx 304正常的，它的返回值才是调用接口的地方收到的数据
  (res) => {
    // console.log('response响应拦截器', res)
    if (res.data.code !== 10000) {
      showFailToast(res.data.message || '网络出错')
      const store = useUserStore()
      store.delUser()
      return Promise.reject(res.data)
    }
    // 3. 移除axios包装的对象，再去res.data，这个是当前接口的返回值
    return res.data
  },
  // 4. http网络状态码 4xx 5xx 异常的
  (err) => {
    console.log('网络4xx, 5xx的情况:', err)
    if (err.response.status === 401) {
      showFailToast('身份信息失效，请重新登录')
      router.push({
        path: '/login',
        query: {
          returnUrl: router.currentRoute.value.fullPath
        }
      })
    } else {
      showFailToast('网络异常')
    }
  }
)

// export default instance

type data<T> = {
  code: number
  message: string
  data: T
}

// JS的数据类型：object对象类型，存储的是键值对，域名只能是字符串，平时我们写的键名不带引号，是因为键名如果是合法的变量名时可以简略的忽略不写引号
// 属性名是合法的变量名才可以用简化的 '.' 语法
const request = <T>(
  url: string,
  method: Method = 'GET',
  requestData?: object
) => {
  // 第一个参数T描述的是接口真正的返回值的类型 接口数据.data这一层
  // 第二个参数R(data<T>)描述的是接口返回值的数据的类型
  return instance<T, data<T>>({
    url: url,
    method: method,
    [method.toLowerCase() === 'get' ? 'params' : 'data']: requestData
  })
}
export default request
